{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 了解Julia\n",
    "\n",
    "\n",
    "这个notebook用于速成Julia语法，让你了解Julia是怎么着轻量级、怎么着好用——就像你最喜欢的高级语言一样！\n",
    "\n",
    "将涉及：\n",
    "- Strings 字符串\n",
    "- Data structures 数据结构\n",
    "- Loops 循环\n",
    "- Conditionals 条件判断\n",
    "- Functions 函数"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Strings 字符串"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "string1 = \"How many cats \""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "string2 = \"is too many cats?\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "string(string1, string2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "😺 = 10\n",
    "println(\"I don't know but $😺 are too few!\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "注意：Julia允许用超广泛的字符，就比如😺\n",
    "\n",
    "这就让我们可以把代码写成这个样子"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "😺 = 1\n",
    "😀 = 0\n",
    "😞 = -1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "😺 + 😞 == 😀"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Data structures 数据结构"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Tuples 元组\n",
    "\n",
    "要创建创建一个元组，用小括号`( )`括起一系列顺序的元素\n",
    "\n",
    "\n",
    "语法： <br>\n",
    "```julia\n",
    "(item1, item2, ...)```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "myfavoriteanimals = (\"penguins\", \"cats\", \"sugargliders\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "myfavoriteanimals[1]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Dictionaries 字典\n",
    "\n",
    "想存键值对，用字典。通过`Dict()`函数来创建字典。\n",
    "\n",
    "语法：\n",
    "```julia\n",
    "Dict(key1 => value1, key2 => value2, ...)```\n",
    "\n",
    "比如存电话簿，人名和电话号码成键值对关系"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "myphonebook = Dict(\"Jenny\" => \"867-5309\", \"Ghostbusters\" => \"555-2368\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "myphonebook[\"Jenny\"]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Arrays 数组\n",
    "\n",
    "不同于元组，数组可变；不同于字典，数组元素有顺序。 <br>\n",
    "要创建创建一个数组，用方括号`[ ]`括起一系列顺序的元素。\n",
    "\n",
    "Syntax: <br>\n",
    "```julia\n",
    "[item1, item2, ...]```\n",
    "\n",
    "像这样："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "myfriends = [\"Ted\", \"Robyn\", \"Barney\", \"Lily\", \"Marshall\"]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fibonacci = [1, 1, 2, 3, 5, 8, 13]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "mixture = [1, 1, 2, 3, \"Ted\", \"Robyn\"]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "数组可以包含其他数据结构，也可以包含数据变成高维数组"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "numbers = [[1, 2, 3], [4, 5], [6, 7, 8, 9]]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "rand(4, 3)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Loops 循环\n",
    "\n",
    "### `for`循环\n",
    "\n",
    "`for`循环语法：\n",
    "\n",
    "```julia\n",
    "for *var* in *loop iterable*\n",
    "    *loop body*\n",
    "end\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "for n in 1:10\n",
    "    println(n)\n",
    "end"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### `while`循环\n",
    "\n",
    "`while`循环语法：\n",
    "\n",
    "```julia\n",
    "while *condition*\n",
    "    *loop body*\n",
    "end\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "n = 0\n",
    "while n < 10\n",
    "    n += 1\n",
    "    println(n)\n",
    "end"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Conditionals 条件判断\n",
    "\n",
    "#### `if`语法\n",
    "\n",
    "Julia中if语法为：\n",
    "\n",
    "```julia\n",
    "if *condition 1*\n",
    "    *option 1*\n",
    "elseif *condition 2*\n",
    "    *option 2*\n",
    "else\n",
    "    *option 3*\n",
    "end\n",
    "```\n",
    "\n",
    "这让我们可以按条件执行不同的语句"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x, y = 1, 2\n",
    "if x > y\n",
    "    x\n",
    "else\n",
    "    y\n",
    "end"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 三元运算符\n",
    "\n",
    "我们可以用三元运算符语法重写上一个cell\n",
    "\n",
    "```julia\n",
    "a ? b : c\n",
    "```\n",
    "\n",
    "它等价于\n",
    "\n",
    "```julia\n",
    "if a\n",
    "    b\n",
    "else\n",
    "    c\n",
    "end\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "(x > y) ? x : y"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Functions 函数\n",
    "\n",
    "话题：\n",
    "1. 如何声明一个函数\n",
    "2. Julia中的鸭子类型（Duck-typing）\n",
    "3. 原地修改与非原地修改函数 Mutating vs. non-mutating functions\n",
    "4. 高阶函数\n",
    "\n",
    "### 如何声明一个函数\n",
    "\n",
    "#### 方法一：用`function` 和 `end` 关键字"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "function f(x)\n",
    "    x^2\n",
    "end"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 方法二：用`=`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "f2(x) = x^2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "方法三：匿名函数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "f3 = x -> x^2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 调用函数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "f(42)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "f2(42)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "f3(42)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Julia中的鸭子类型（Duck-typing）\n",
    "*“假如它嘎嘎像个鸭鸭，那它就是个鸭鸭”* <br><br>\n",
    "不管输入参数是什么类型，只要能用，那么Julia函数就能使 <br><br>\n",
    "比如上面的`f`函数可以接受一个矩阵（matrix）作为参数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "A = rand(3, 3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "f(A)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "然而，`f`函数无法接受一个向量（vector）。不同于`A^2`是已经定义好的矩阵乘方，当`v`是向量时的`v^2`是有歧义的。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "v = rand(3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "f(v)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 原地修改与非原地修改函数 Mutating vs. non-mutating functions\n",
    "\n",
    "约定：函数名以`!`结束的原地修改传入的变量，函数名非以`!`结束的则不会改变传入的变量。\n",
    "\n",
    "例如下面的`sort`和`sort!`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "v = [3, 5, 2]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "sort(v)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "v"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`sort(v)`会返回一个新的、将`v`排序后的数组，`v`本身不会改变 <br><br>\n",
    "\n",
    "而当执行`sort!(v)`后，`v`将会被原地排序修改"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "sort!(v)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "v"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 一些高阶函数\n",
    "\n",
    "#### map\n",
    "\n",
    "`map`是Julia中的高阶函数。“高阶”指的是它会*接受一个函数*作为它的传入参数。\n",
    "`map`将传入的函数作用于传入的数据结构的每一个元素。例如执行\n",
    "\n",
    "```julia\n",
    "map(f, [1, 2, 3])\n",
    "```\n",
    "将得到一个输出数组，数组的每一个元素为`f`作用在数组`[1, 2, 3]`的对应元素\n",
    "```julia\n",
    "[f(1), f(2), f(3)]\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "map(f, [1, 2, 3])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这里我们把向量`[1, 2, 3]`的每一个元素都平方了，而不是对向量`[1, 2, 3]`本身进行平方。\n",
    "\n",
    "`map`可以接受匿名函数作为参数，像这样"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "map(x -> x^3, [1, 2, 3])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "这就完成了对数组`[1, 2, 3]`所有元素的三次方计算！"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### broadcast\n",
    "\n",
    "`broadcast`和`map`一样也是个高阶函数。`broadcast`一种广义化的`map`,所以`map`能做的它都能做，并不止如此。`broadcast`的调用方法和`map`一样。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "broadcast(f, [1, 2, 3])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "我们又一次通过函数`f`把向量`[1, 2, 3]`的每一个元素都平方了——这次是用“广播”函数`f`的方式！\n",
    "\n",
    "`broadcast`有个语法糖：调用要广播的函数时在函数名和输入变量之间加一个`.`。比如：\n",
    "\n",
    "```julia\n",
    "broadcast(f, [1, 2, 3])\n",
    "```\n",
    "就等价于\n",
    "```julia\n",
    "f.([1, 2, 3])\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "f.([1, 2, 3])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "再一次强调`map`和`broadcast`方式与如下直接调用函数的区别\n",
    "```julia\n",
    "f([1, 2, 3])\n",
    "```\n",
    "我们可以求向量中每个元素的平方，但是不能求向量的平方！"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "为了再讲清楚这一点，我们再看一下以下调用的区别\n",
    "\n",
    "```julia\n",
    "f(A)\n",
    "```\n",
    "与\n",
    "```julia\n",
    "f.(A)\n",
    "```\n",
    "其中`A`是个矩阵："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "A = [i + 3*j for j in 0:2, i in 1:3]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "f(A)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "和之前一样，对于矩阵`A`来说\n",
    "```\n",
    "f(A) = A^2 = A * A\n",
    "``` \n",
    "\n",
    "另一方面，"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "B = f.(A)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "包含了矩阵`A`中每个元素的平方\n",
    "\n",
    "广播的点语法让比较复杂的元素间运算的表示更自然、更贴近数学表示，比如："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "C = A .+ 2 .* f.(A) ./ A"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "而不是"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "broadcast(x -> x + 2 * f(x) / x, A)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "并且这么写仍然能编译到和C语言一样高效的代码！"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Julia 1.0.5",
   "language": "julia",
   "name": "julia-1.0"
  },
  "language_info": {
   "file_extension": ".jl",
   "mimetype": "application/julia",
   "name": "julia",
   "version": "1.0.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
